import {computed, createStore, designPage, reactive} from "@peryl/react-compose";
import {$dialog, $message, $notice, Button, ButtonGroup, Dropdown, DropdownOption, Icon, Input, InputGroup, Layout, LayoutSection, LoadingMask, PageCard, PageCardContent, Space, Tooltip} from "plain-design";
import {env} from "../../env";
import {formatRuleResultList, iRuleRecord, iRuleResultRecord, RuleList} from "./RuleList";
import {RuleDetail} from "./RuleDetail";
import {http} from "../../modules/plain-design/http";
import {deepcopy} from "@peryl/utils/deepcopy";
import {RuleListPageEditor} from "./RuleListPageEditor";
import {createDefaultRuleEntity, RuleReturnCode} from '@peryl/react-cms-editor';
import './rule-list-page.scss';
import {createPageQuery, useSetupEffects} from "../../modules/base/createPageQuery";

export default designPage(() => {

  const { setupEffects } = useSetupEffects();

  const ruleRecordManager = (() => {

    const pageQuery = createPageQuery<iRuleRecord>({ effects: setupEffects, url: '/rule/list', requestParams: { orders: [{ field: 'createdAt', desc: true }] } });
    pageQuery.hooks.onAfterReload.use(() => {updateCurrentRule(pageQuery.state.data[0]);});
    pageQuery.reload();

    const state = reactive({
      /*
      * 当前选中的规则的索引，之所以用索引来设计选中规则，而不是直接存一条规则数据
      * 是因为直接存一条规则数据的话，当更新列表数据，与更新选中数据会不同步，state.data中
      * 选中的数据，与state.currentRule可能会变成两个不同的对象，导致后续的显示更新等操作出现数据异常
      */
      current: null as null | number,
    });

    /*当前选中的规则数据*/
    const currentRule = computed((): iRuleRecord | undefined => state.current == null ? undefined : pageQuery.state.data[state.current]);

    /**
     * 创建一条新的规则
     * @author  wsj
     * @date    2024/10/16 3:00
     */
    const createRuleRecord = async (initialRuleRecord?: Partial<iRuleRecord>) => {
      if (!initialRuleRecord) {
        const { ruleEntity: { ruleMetas, ruleVariables } } = createDefaultRuleEntity();
        ruleVariables[RuleReturnCode].readonly = false;
        initialRuleRecord = { jsonData: { ruleMetas, ruleVariables } };
      }
      const newRuleRecord = await RuleDetail.openEditor(initialRuleRecord);
      const resp = await http.post<{ result: iRuleRecord }>('/rule/insert', { row: newRuleRecord });
      pageQuery.state.data.unshift(resp.result);
      await updateCurrentRule(pageQuery.state.data[0]);
      $message.success('新建成功');
    };

    /**
     * 编辑已有的规则信息
     * @author  wsj
     * @date    2024/10/16 3:12
     */
    const editRuleRecord = async (targetRuleRecord: iRuleRecord) => {
      const newRuleRecord = await RuleDetail.openEditor(targetRuleRecord, 'edit');
      return requestUpdateRuleRecord(newRuleRecord);
    };

    /**
     * 发送请求保存规则记录
     * @author  wsj
     * @date    2024/10/17 13:37
     */
    const requestUpdateRuleRecord = async (targetRuleRecord: Partial<iRuleRecord>) => {
      const resp = await http.post<{ result: iRuleRecord }>('/rule/update', { row: targetRuleRecord });
      const index = pageQuery.state.data.findIndex(i => i.id === targetRuleRecord.id);
      if (index > -1) {pageQuery.state.data[index] = resp.result;}
      $message.success('保存成功');
    };

    /**
     * 复制一个规则
     * @author  wsj
     * @date    2024/10/16 3:14
     */
    const duplicateRecord = async (targetRuleRecord: iRuleRecord) => {
      const initialRuleRecord: Partial<iRuleRecord> = deepcopy(targetRuleRecord);
      delete initialRuleRecord.id;
      delete initialRuleRecord.createdAt;
      delete initialRuleRecord.createdBy;
      delete initialRuleRecord.updatedAt;
      delete initialRuleRecord.updatedBy;
      return createRuleRecord(initialRuleRecord);
    };

    /**
     * 删除一条规则
     * @author  wsj
     * @date    2024/10/16 3:21
     */
    const deleteRecord = async (targetRuleRecord: iRuleRecord) => {
      await $dialog.confirm(`确认删除规则：${targetRuleRecord.name}?`);
      /*删除规则数据*/
      await http.post<{ result: iRuleRecord }>('/rule/delete', { id: targetRuleRecord.id });
      /*删除规则的日志*/
      await (async () => {
        const resp = await http.post<{ list: iRuleResultRecord[] }>('/rule_result/list', { all: true, filters: [{ field: 'parentRuleId', value: targetRuleRecord.id, operator: '=' }] });
        await Promise.all(resp.list.map(async i => {await http.post('/rule_result/delete', { id: i.id });}));
      })();
      /*删除列表中的规则数据*/
      const index = pageQuery.state.data.findIndex(i => i.id === targetRuleRecord.id);
      index > -1 && pageQuery.state.data.splice(index, 1);
      /*
      * 如果删除记录就是当前选中的记录，那么就自动选中下一条记录(如果没有下一条记录了，就自动选中上一条)
      * 如果不是当前选中的记录，那么不做任何处理
      */
      if (targetRuleRecord.id === currentRule.value?.id) {
        if (!!pageQuery.state.data[index]) {
          await updateCurrentRule(pageQuery.state.data[index]);
        } else {
          await updateCurrentRule(pageQuery.state.data[index - 1]);
        }
      }
      $message.success('删除成功');
    };

    /**
     * 更新当前选中的规则
     * @author  wsj
     * @date    2024/10/16 3:01
     */
    const updateCurrentRule = async (targetRule: iRuleRecord | null) => {
      if (!!currentRule.value && targetRule && currentRule.value.id === targetRule.id) {
        /*如果选中的是同一条rule，则清理掉current result, 令 Rule Editor显示rule的数据而不是result的数据*/
        resultRecordManager.state.current = null;
      } else {
        const index = !targetRule ? 0 : pageQuery.state.data.findIndex(i => i.id === targetRule.id);
        if (index > -1) {
          resultRecordManager.clearRuleResults();
          state.current = index;
          await resultRecordManager.reloadRuleResults(currentRule.value?.id);
        } else {
          console.error(`Can't update current rule`, targetRule);
        }
      }
    };

    const filterRules = computed(() => {
      if (!searchRule.state.searchText.trim().length) {
        return pageQuery.state.data;
      } else {
        const searchText = searchRule.state.searchText.trim().toLowerCase();
        return pageQuery.state.data.filter(item => [item.name, item.comments, item.createdAt, item.updatedAt].some(
          i => !!i && i.toLowerCase().indexOf(searchText) > -1
        ));
      }
    });

    const handler = {
      onSaveRuleData: async (saveData: iRuleRecord['jsonData']) => {
        if (!currentRule.value) {
          $notice.error('数据异常，保存失败！');
          return;
        }
        currentRule.value.jsonData = saveData;
        await requestUpdateRuleRecord(currentRule.value);
      },
      onRuleEditorRunFinish: async (newRuleResultRecord: Partial<iRuleResultRecord>) => {
        const saveRuleResultRecord = await resultRecordManager.saveNewRuleResultRecord(newRuleResultRecord);
        if (!!saveRuleResultRecord) {
          resultRecordManager.updateCurrentResult(saveRuleResultRecord);
        }
      },
    };

    return {
      state,
      createRuleRecord,
      editRuleRecord,
      duplicateRecord,
      deleteRecord,
      updateCurrentRule,
      filterRules,
      handler,
      currentRule,
      pageQuery,
    };
  })();

  const resultRecordManager = (() => {

    const pageQuery = createPageQuery<iRuleResultRecord>({ effects: setupEffects, url: '/rule_result/list', requestParams: { orders: [{ field: 'createdAt', desc: true }] } });
    pageQuery.hooks.onAfterLoad.use((data) => {formatRuleResultList(data.list);});

    const state = reactive({
      /*当前选中的日志*/
      current: null as null | number,
    });

    const currentResult = computed(() => state.current == null ? undefined : pageQuery.state.data[state.current]);

    /**
     * 更新当前选中的日志
     * @author  wsj
     * @date    2024/10/16 3:01
     */
    const updateCurrentResult = (targetResult: iRuleResultRecord) => {
      const index = pageQuery.state.data.findIndex(i => i.id === targetResult.id);
      if (index > -1) {
        state.current = index;
      } else {
        console.error(`Can't update current result`, targetResult);
      }
    };

    /**
     * 清理选中的日志对象
     * @author  wsj
     * @date    2024/10/21 13:23
     */
    const clearCurrentResult = () => {state.current = null;};

    /**
     * 保存一条规则执行结果数据
     * @author  wsj
     * @date    2024/10/17 21:19
     */
    const saveNewRuleResultRecord = async (newRuleResultRecord: Partial<iRuleResultRecord>) => {
      const parentRuleId = ruleRecordManager.currentRule.value?.id;
      if (!parentRuleId) {
        $notice.error(`当前无选中规则，保存执行结果失败！`);
        return;
      }
      newRuleResultRecord.parentRuleId = parentRuleId;
      const resp = await http.post<{ result: iRuleResultRecord }>('/rule_result/insert', { row: newRuleResultRecord });
      const saveRuleResultRecord = resp.result;
      formatRuleResultList(saveRuleResultRecord);
      if (ruleRecordManager.currentRule.value?.id === parentRuleId) {
        pageQuery.state.data.unshift(saveRuleResultRecord);
        return saveRuleResultRecord;
      }
      return null;
    };

    /**
     * 清理日志列表数据信息
     * @author  wsj
     * @date    2024/10/17 21:43
     */
    const clearRuleResults = () => {
      pageQuery.state.data = [];
      clearCurrentResult();
      pageQuery.state.loading = null;
    };

    /**
     * 重新加载日志列表数据信息
     * @author  wsj
     * @date    2024/10/17 21:43
     */
    const reloadRuleResults = async (parentRuleId: string | undefined) => {
      if (!parentRuleId) {
        clearRuleResults();
      } else {
        await pageQuery.reload({
          requestParams: {
            orders: [{ field: 'createdAt', desc: true }],
            filters: [{ field: 'parentRuleId', value: parentRuleId, operator: '=' }]
          }
        });
      }
    };

    return { state, currentResult, updateCurrentResult, saveNewRuleResultRecord, reloadRuleResults, clearCurrentResult, clearRuleResults, pageQuery };
  })();

  const searchRule = (() => {
    const state = reactive({
      isSearching: false,
      searchText: ''
    });

    const handler = {
      onSearchBlur: () => {
        if (!state.searchText?.trim().length) {state.isSearching = false;}
      },
      show: () => {state.isSearching = true;},
    };

    return { state, handler, };
  })();

  return () => (
    <PageCard full className="rule-list-page">
      <PageCardContent full noPadding>
        <Layout fullHeight>
          <LayoutSection position="left" v-model={layoutCache.value.size.left} className="rule-list-data-section" noPadding>
            <Layout fullHeight vertical>
              <LayoutSection position="top" v-model={layoutCache.value.size.headerList} fixedInner className="rule-list-section" noPadding>
                <RuleList
                  title={searchRule.state.isSearching ? "" : "规则列表"}
                  data={ruleRecordManager.filterRules.value}
                  loading={ruleRecordManager.pageQuery.isLoading()}
                  onVerticalScrollBottom={ruleRecordManager.pageQuery.loadNextPage}
                  v-slots={{
                    operation: () => (
                      searchRule.state.isSearching ?
                        (
                          <InputGroup size="mini">
                            <Input v-model={searchRule.state.searchText} prefixIcon="pi-search" autoFocus inputMode="stroke" width="100%" onBlur={searchRule.handler.onSearchBlur} placeholder="规则名称/创建时间/备注说明"/>
                            <Tooltip message="创建规则"><Button icon="pi-plus" onClick={() => ruleRecordManager.createRuleRecord()}/></Tooltip>
                          </InputGroup>
                        ) : (
                          <ButtonGroup size="mini">
                            <Tooltip message="搜索规则"><Button icon="pi-search" onClick={searchRule.handler.show}/></Tooltip>
                            <Tooltip message="创建规则"><Button icon="pi-plus" onClick={() => ruleRecordManager.createRuleRecord()}/></Tooltip>
                          </ButtonGroup>
                        )
                    ),
                    default: ({ item, vIndex }) => {
                      const record = item as iRuleRecord;
                      return (
                        <div
                          data-vid={vIndex}
                          key={vIndex}
                          className="rule-list-item"
                          data-current-rule={String(record.id === ruleRecordManager.currentRule.value?.id)}
                          onClick={() => ruleRecordManager.updateCurrentRule(record)}
                        >
                          <div className="rule-list-item-inner">
                            <div className="rule-list-item-label">
                              <div className="rule-list-item-name">
                                <span>{record.name}</span>
                                {!record.comments?.length ? null : <Tooltip message={record.comments}>
                                  <Icon icon="pi-info-circle"/>
                                </Tooltip>}
                              </div>
                              <span className="rule-list-item-time">{record.createdAt}</span>
                            </div>
                            <div className="rule-list-item-operation">
                              <Dropdown
                                placement="bottom"
                                trigger="hover"
                                v-slots={{
                                  default: () => <Icon icon="pi-more"/>,
                                  popper: () => <>
                                    <DropdownOption label="编辑" onClick={() => ruleRecordManager.editRuleRecord(record)}/>
                                    <DropdownOption label="复制" onClick={() => ruleRecordManager.duplicateRecord(record)}/>
                                    <DropdownOption label="删除" onClick={() => ruleRecordManager.deleteRecord(record)}/>
                                  </>
                                }}
                              />
                            </div>
                          </div>
                        </div>
                      );
                    },
                  }}
                />
              </LayoutSection>
              <LayoutSection fixedInner className="rule-result-section" noPadding>
                <RuleList
                  key={ruleRecordManager.currentRule.value?.id || "_"}
                  title="规则日志"
                  data={resultRecordManager.pageQuery.state.data}
                  onVerticalScrollBottom={resultRecordManager.pageQuery.loadNextPage}
                  loading={
                    ruleRecordManager.pageQuery.isLoading() ||
                    resultRecordManager.pageQuery.isLoading()
                  }
                  v-slots={{
                    operation: () => (
                      <Tooltip message="刷新"><Button size="mini" icon="pi-refresh" onClick={() => resultRecordManager.pageQuery.reload()}/></Tooltip>
                    ),
                    default: ({ item, vIndex }) => {
                      const resultRecord = item as iRuleResultRecord;
                      return (
                        <div
                          className="rule-list-result-item"
                          key={vIndex}
                          data-vid={vIndex}
                          data-rule-result-status={resultRecord.flag ? 'success' : 'error'}
                          data-current-result={String(resultRecord.id === resultRecordManager.currentResult.value?.id)}
                          onClick={() => {resultRecordManager.updateCurrentResult(resultRecord);}}
                        >
                          <div className="rule-list-result-item-inner">
                            <Space vertical size="mini">
                              <div className="rule-list-result-item-time">
                                <span>{resultRecord.startTime}</span>
                                <span> ~ </span>
                                <span>{resultRecord.endTime}</span>
                              </div>
                              <div className="rule-list-result-item-return">
                                返回:{(() => {
                                const resultString = JSON.stringify(resultRecord.returnValue || '无');
                                if (resultString.length > 200) {
                                  return <>
                                    <span>{resultString.slice(0, 200) + '...'}</span>
                                    <Button mode="text" label="查看全部" onClick={e => {
                                      e.stopPropagation();
                                      $dialog({
                                        editType: 'textarea',
                                        editValue: resultString,
                                      });
                                    }}/>
                                  </>;
                                } else {
                                  return resultString;
                                }
                              })()}
                              </div>
                              <div className="rule-list-result-item-msg">
                                信息:{resultRecord.msg || '无'}
                              </div>
                            </Space>
                          </div>
                        </div>
                      );
                    }
                  }}
                />
              </LayoutSection>
            </Layout>
          </LayoutSection>
          <LayoutSection fixedInner className="rule-list-editor-section" noPadding>
            {(ruleRecordManager.pageQuery.isLoading() || ruleRecordManager.pageQuery.isEmpty()) ? (
              <PageCard full>
                <PageCardContent full>
                  <LoadingMask modelValue={ruleRecordManager.pageQuery.isLoading()}/>
                  {!ruleRecordManager.pageQuery.isLoading() && ruleRecordManager.pageQuery.isEmpty() && (
                    <div className="rule-list-empty-button">
                      <Button icon="pi-plus" label="新建规则" mode="fill" onClick={() => ruleRecordManager.createRuleRecord()}/>
                    </div>
                  )}
                </PageCardContent>
              </PageCard>
            ) : (
              !resultRecordManager.currentResult.value ?
                (
                  <RuleListPageEditor
                    key={ruleRecordManager.currentRule.value?.id || 'empty'}
                    ruleMetas={ruleRecordManager.currentRule.value?.jsonData?.ruleMetas}
                    ruleVariables={ruleRecordManager.currentRule.value?.jsonData?.ruleVariables}
                    onSave={ruleRecordManager.handler.onSaveRuleData}
                    onRunFinish={ruleRecordManager.handler.onRuleEditorRunFinish}
                  />
                ) :
                (
                  <RuleListPageEditor
                    key={resultRecordManager.currentResult.value.id}
                    ruleMetas={resultRecordManager.currentResult.value.meta}
                    ruleVariables={resultRecordManager.currentResult.value.variables}
                    initializeVariablesWithInitialValue
                    disable
                    showBackButton
                    onCallBack={resultRecordManager.clearCurrentResult}
                  />
                )
            )}
          </LayoutSection>
        </Layout>
      </PageCardContent>
    </PageCard>
  );
});

const layoutCache = createStore({
  initialState: {
    size: {
      left: 325,
      headerList: Math.ceil(document.body.offsetHeight / 2)
    }
  },
  getCacheConfig: () => ({
    cacheName: 'rule_list_layout',
    envName: env.envName,
  })
});
